package cn.dengta.webapp.user.model;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;

import cn.dengta.common.context.I18N;
import cn.dengta.common.model.ValueProxy;
import cn.dengta.common.model.ValueProxyImpl;
import cn.dengta.common.util.Validators;
import cn.dengta.context.model.*;
import lombok.Getter;
import me.codeplayer.util.*;
import org.apache.commons.lang3.StringUtils;

@Getter
public enum PhoneArea implements ValueProxyImpl<PhoneArea, String> {
	// 亚洲-----------------------
	/** 香港 */
	HK(Country.HK, "852", 8, Set.of(WesKit.main)),
	/** 中国大陆 */
	CN(Country.CN, "86", 11, 11, true, Set.of(WesKit.main)),
	/** 台湾 */
	TW(Country.TW, "886", 9, 10, Set.of(WesKit.main)),
	/** 越南 */
	VN(Country.VN, "84", 9, 11, Set.of(WesKit.main)),
	/** 澳门 */
	MO(Country.MO, "853", 8, Set.of(WesKit.main)),
	/** 日本 */
	JP(Country.JP, "81", 10, 11, Set.of(WesKit.main)),
	/** 韩国 */
	KR(Country.KR, "82", 10, 11, Set.of(WesKit.main)),
	/** 泰国 */
	TH(Country.TH, "66", 9, 10, Set.of(WesKit.main)),
	/** 印尼 */
	ID(Country.ID, "62", 10, 13, Set.of(WesKit.main)),
	/** 印度 */
	IN(Country.IN, "91", 9, 10, Set.of(WesKit.main)),
	/** 菲律宾 */
	PH(Country.PH, "63", 9, 10, Set.of(WesKit.main)),
	/** 马来西亚 */
	MY(Country.MY, "60", 9, 10, Set.of(WesKit.main)),

	// 北美--------------------
	/** 美国 */
	US(Country.US, "1", 10, 10, Set.of()),
	/** 加拿大 */
	CA(Country.CA, "1", 10, 10, Set.of()),

	// 拉美-------------------
	/** 墨西哥 */
	MX(Country.MX, "52", 10, 10, Set.of()),
	/** 阿根廷 */
	AR(Country.AR, "54", 10, 10, Set.of()),
	/** 巴西 */
	BR(Country.BR, "55", 9, 11, Set.of()),
	/** 智利 */
	CL(Country.CL, "56", 9, 9, Set.of()),
	/** 哥伦比亚 */
	CO(Country.CO, "57", 10, 10, Set.of()),
	/** 委内瑞拉 */
	VE(Country.VE, "58", 10, 10, Set.of()),
	/** 秘鲁 */
	PE(Country.PE, "51", 10, 10, Set.of()),
	/** 厄瓜多尔 */
	EC(Country.EC, "593", 7, 7, Set.of()),
	/** 危地马拉 */
	GT(Country.GT, "502", 8, 8, Set.of()),
	/** 萨尔瓦多 */
	SV(Country.SV, "503", 8, 8, Set.of()),
	/** 哥斯达黎加 */
	CR(Country.CR, "506", 8, 8, Set.of()),
	/** 古巴 */
	CU(Country.CU, "506", 8, 8, Set.of()),
	/** 多米尼加共和国 */
	DO(Country.DO, "1-809", 7, 7, Set.of()),
	/** 海地 */
	HT(Country.HT, "509", 8, 8, Set.of()),
	/** 洪都拉斯 */
	HN(Country.HN, "504", 8, 8, Set.of()),
	/** 尼加拉瓜 */
	NI(Country.NI, "505", 8, 8, Set.of()),
	/** 巴拿马 */
	PA(Country.PA, "507", 8, 8, Set.of()),
	/** 巴拉圭 */
	PY(Country.PY, "595", 9, 9, Set.of()),
	/** 波多黎各 */
	PR(Country.PR, "1-787", 7, 7, Set.of()),
	/** 乌拉圭 */
	UY(Country.UY, "598", 8, 8, Set.of()),

	// 欧洲-----------------------
	/** 英国 */
	GB(Country.GB, "44", 10, 10, Set.of()),
	/** 法国 */
	FR(Country.FR, "33", 9, 9, Set.of()),
	/** 德国 */
	DE(Country.DE, "49", 11, 11, Set.of()),
	/** 意大利 */
	IT(Country.IT, "39", 10, 10, Set.of()),
	/** 西班牙 */
	ES(Country.ES, "34", 9, 9, Set.of()),
	/** 荷兰 */
	NL(Country.NL, "31", 9, 11, Set.of()),
	/** 比利时 */
	BE(Country.BE, "32", 9, 9, Set.of()),
	/** 瑞士 */
	CH(Country.CH, "41", 9, 9, Set.of()),
	/** 波兰 */
	//	PL("48", 9, 9, Set.of(WesKit.contala, WesKit.holaMet)),
	/** 希腊 */
	GR(Country.GR, "30", 10, 10, Set.of()),
	/** 俄罗斯 */
	//	RU("7", 10, 10, Set.of(WesKit.contala, WesKit.holaMet)),
	/** 冰岛 */
	IS(Country.IS, "354", 7, 7, Set.of()),
	/** 葡萄牙 */
	PT(Country.PT, "351", 9, 9, Set.of()),
	/** 奥地利 */
	AT(Country.AT, "43", 10, 10, Set.of()),
	/** 丹麦 */
	DK(Country.DK, "45", 8, 8, Set.of()),
	/** 爱尔兰 */
	IE(Country.IE, "353", 9, 9, Set.of()),
	/** 芬兰 */
	FI(Country.FI, "358", 9, 10, Set.of()),
	/** 挪威 */
	NO(Country.NO, "47", 8, 8, Set.of()),
	/** 瑞典 */
	SE(Country.SE, "46", 9, 9, Set.of()),

	// 北非 -----------------
	/** 埃及 */
	EG(Country.EG, "20", 10, 10, Set.of()),
	/** 阿尔及利亚 */
	DZ(Country.DZ, "213", 9, 9, Set.of()),
	/** 利比亚 */
	LY(Country.LY, "218", 7, 7, Set.of()),
	/** 摩洛哥 */
	MA(Country.MA, "212", 9, 9, Set.of()),
	/** 苏丹 */
	SD(Country.SD, "249", 7, 7, Set.of()),
	/** 突尼斯 */
	TN(Country.TN, "216", 8, 8, Set.of()),
	/** 毛里塔尼亚 */
	MR(Country.MR, "222", 8, 8, Set.of()),

	;

	public final String code;
	public final Integer minLen;
	public final Integer maxLen;
	public final boolean enabled;
	public final Country country;
	/** 支持的分包 */
	public final Set<WesKit> wesKits;

	final ValueProxy<PhoneArea, String> proxy;
	public static final String sep = "-";

	PhoneArea(Country country, String code, Integer minLen, Integer maxLen, boolean enabled, Set<WesKit> wesKits) {
		this.country = country;
		this.code = code;
		this.minLen = minLen;
		this.maxLen = maxLen;
		this.enabled = enabled;
		this.wesKits = wesKits;
		this.proxy = new ValueProxy<>(this, code, name());
	}

	PhoneArea(Country country, String code, Integer minLen, Integer maxLen, Set<WesKit> wesKits) {
		this(country, code, minLen, maxLen, true, wesKits);
	}

	PhoneArea(Country country, String code, Integer minLen, Set<WesKit> wesKits) {
		this(country, code, minLen, minLen, true, wesKits);
	}

	public boolean isEnabled() {
		return enabled;
	}

	public static boolean match(String phone) {
		return parse(phone, true) != null;
	}

	@Nullable
	public static PhoneArea parse(String phone, boolean areaCodeRequired) {
		if (StringUtil.isEmpty(phone)) {
			return null;
		}
		String[] phoneParts = StringUtils.split(phone, sep);
		switch (phoneParts.length) {
			case 1:
				return !areaCodeRequired && CN.isEnabled() && Validators.matchPhone(phone) ? CN : null;
			case 2: {
				final PhoneArea area = of(phoneParts[0]);
				return area != null && area.enabled
						&& Cmp.between(phoneParts[1].length(), area.minLen, area.maxLen) && NumberUtil.isNumber(phoneParts[1]) ? area : null;
			}
		}
		return null;
	}

	@Nullable
	public static PhoneArea parse(String phone) {
		return parse(phone, true);
	}

	@Nullable
	public static PhoneArea extract(String phone) {
		return PhoneArea.of(resolveCode(phone));
	}

	public static String removeCode(String phone) {
		return StringUtils.substringAfterLast(phone, sep);
	}

	public static String resolveCode(String phone) {
		return StringUtils.substringBefore(phone, sep);
	}

	public boolean has(String phone) {
		if (phone == null) {
			return false;
		}
		final int prefixLength = code.length();
		return phone.length() > prefixLength && phone.charAt(prefixLength) == '-' && phone.startsWith(code);
	}

	public static boolean forChina(String phone) {
		return PhoneArea.CN.has(phone);
	}

	public static PhoneArea[] CACHE = ArrayUtil.filter(values(), p -> p != PhoneArea.CN);

	public static PhoneArea[] CACHE_ALL = values();

	public static PhoneArea[] ANDROID_CACHE = ArrayUtil.filter(values(), c -> c != CN && c.isEnabled());

	public static PhoneArea of(String value) {
		PhoneArea area = HK.getValueOf(value);
		return area != null && area.isEnabled() ? area : null;
	}

	public static String filter(String phone, boolean assertValid) {
		final PhoneArea pa = parse(phone, true);
		if (assertValid) {
			I18N.assertNotNull(pa, UserI18nKey.PHONE_FORMAT_ERROR);
			return pa.clip(phone);
		}
		return phone;
	}

	public String clip(String phone) {
		if (this == VN && phone.regionMatches(2, "-0", 0, 2)) {
			// 统一去掉前置 0
			return phone.replace("-0", "-");
		}
		return phone;
	}

	public static boolean eqPhone(String old, String phone) {
		if (old.equals(phone)) {
			return true;
		} else if (old.length() != phone.length() && PhoneArea.VN.has(phone) && old.regionMatches(0, phone, 0, 3)) {
			return old.length() > phone.length() ? PhoneArea.VN.clip(old).equals(phone) : old.equals(PhoneArea.VN.clip(phone));
		}
		return false;
	}

	public static Set<PhoneArea> ofWesKits(WesKit wesKit) {
		if (wesKit == null) {
			return Set.of(CACHE_ALL);
		}
		return Arrays.stream(CACHE_ALL).filter(p -> X.isValid(p.wesKits) && p.wesKits.contains(wesKit)).collect(Collectors.toSet());
	}

	public static String name2Iso2(String name) {
		if (StringUtil.isEmpty(name)) {
			return "";
		}
		for (PhoneArea phoneArea : values()) {
			if (phoneArea.getCountry().getLabel(Language.zh_CN).equals(name)) {
				return phoneArea.name();
			}
		}
		return "";
	}

}
